package fec
import (
	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/wire"
	"errors"
)

//TODO: maybe the RepairSymbol should have its number in the structure

type FECGroup struct {
	FECGroupNumber       protocol.FECGroup
	RepairSymbols        []*RepairSymbol
	nSentRepairSymbols   uint8
	framesOffset         uint8
	offsetInSymbol       protocol.ByteCount
	packets              [][]byte
	packetIndexes        map[protocol.PacketNumber]int
	version 						 protocol.VersionNumber
	TotalNumberOfPackets int
	TotalNumberOfRepairSymbols int
}

var _ FECContainer = &FECGroup{}

func NewFECGroup(fecGroupNumber protocol.FECGroup, version protocol.VersionNumber) *FECGroup {
	return &FECGroup{
		FECGroupNumber: fecGroupNumber,
		packetIndexes: 	make(map[protocol.PacketNumber]int),
		packets:				make([][]byte, 0),
		version: 				version,
	}
}

var FECGroupPacketAddedToFullFECGroup = errors.New("FECGroup: A packet has been added to an already full FEC Payload")

func (f *FECGroup) ShouldBeSent(c RedundancyController) bool {
	return uint32(len(f.packets)) >= uint32(c.GetNumberOfDataSymbols())
}

func (f *FECGroup) AddPacket(packet []byte,  hdr *wire.Header) {
	if _, ok := f.packetIndexes[hdr.PacketNumber] ; ok {
		return
	}
	packetCopy := make([]byte, protocol.MaxReceivePacketSize)[:len(packet)]
	copy(packetCopy, packet)
	if hdr.FECGroupOffset >= byte(len(f.packets)) {
		delta := int(hdr.FECGroupOffset) - len(f.packets)
		for i := 0 ; i <= delta ; i++ {
			f.packets = append(f.packets, nil)
		}
	}
	f.packets[hdr.FECGroupOffset] = packetCopy
	f.packetIndexes[hdr.PacketNumber] = int(hdr.FECGroupOffset)
	return
}

// Must be called before sending the group
func (f *FECGroup) PrepareToSend() error {
	if len(f.packets) > int(protocol.NumberOfFecPackets) {
		f.TotalNumberOfPackets = 0
		return FECGroupPacketAddedToFullFECGroup
	}
	f.TotalNumberOfPackets = len(f.packets)
	f.TotalNumberOfRepairSymbols = len(f.RepairSymbols)
	for _, r := range f.RepairSymbols {
		r.NumberOfPackets = uint8(f.TotalNumberOfPackets)
		r.NumberOfRepairSymbols = uint8(f.TotalNumberOfRepairSymbols)
	}
	return nil
}

func (f *FECGroup) AddRepairSymbol(symbol *RepairSymbol) error {
	f.RepairSymbols = append(f.RepairSymbols, symbol)
	return nil
}

func (f *FECGroup) HasPacket(packetNumber protocol.PacketNumber) bool {
	_, ok := f.packetIndexes[packetNumber]
	return ok
}

func (f *FECGroup) GetPacketOffset(packetNumber protocol.PacketNumber) byte {
	return byte(f.packetIndexes[packetNumber])
}

func (f *FECGroup) HasFECDataToSend() bool {
	return int(f.nSentRepairSymbols) < len(f.RepairSymbols)
}

func (f *FECGroup) CurrentNumberOfPackets() int {
	return len(f.packetIndexes)
}

func (f *FECGroup) SetRepairSymbols(symbols []*RepairSymbol) {
	for _, s := range symbols {
		s.FECGroup = f.FECGroupNumber
		s.NumberOfRepairSymbols = uint8(len(symbols))
		s.NumberOfPackets = uint8(f.CurrentNumberOfPackets())
	}
	f.RepairSymbols = symbols
}

func (f *FECGroup) GetRepairSymbols() []*RepairSymbol {
	return f.RepairSymbols
}

func (f *FECGroup) GetPackets() [][]byte {
	retVal := make([][]byte, len(f.packets))
	for _, idx := range f.packetIndexes {
		retVal[idx] = f.packets[idx]
	}
	return retVal
}